/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */
#pragma once

#include <xml/Object.h>
#include <vector>
#include <Atom.h>
#include <lib3d/material/TextureSimple.h>
#include <lib3d/material/TextureSequence.h>
#include <utl.h>
#include <lib3d/anim2d/FrameTimes.h>

namespace liba {
namespace lib3d {
namespace hard {
class Hardware;
class RenderTexture;
} // namespace hard
namespace anim2d {

class AbstractSequence : public xml::ObjectANSI
{
public:
	AbstractSequence();
	AbstractSequence(const AbstractSequence& rhs);
	virtual ~AbstractSequence();

	const Atom & get_name() const { return name; }
	double get_height() const { return height; }
	double get_width() const { return width; }
	const FrameTimes& GetFrameTimes() { return this->frameTimes; }

	virtual void render_to_list(hard::Hardware * hardware, hard::RenderTexture * render_texture, unsigned frame_number) = 0;
	virtual size_t get_frames_count() const = 0;

	enum LoopType { NONE, FORWARD, BACKWARD, PINGPONG };
	static converter::EnumPair<char, LoopType> LoopTypeNames[];
	LoopType loop_type;

	double GetLoopDelay() const { return loopDelay; }

	virtual AbstractSequence* clone() const = 0;

	void SetName(const Atom & value)
	{
		name = value;
	}

	void SetWidth(int value)
	{
		width = value;
	}

	void SetHeight(int value)
	{
		height = value;
	}

	void SetFrameTime(double value)
	{
		frame_time = value;
	}

	double GetFrameTime()
	{
		return frame_time;
	}

	unsigned int GetFrameStart()
	{
		return frame_start;
	}

	unsigned int GetFrameEnd()
	{
		return frame_end;
	}

	void SetFrameStart(unsigned int value)
	{
		frame_start = value;
		load_image(image_name);
		ComputeFrameTimes();
	}

	void SetFrameEnd(unsigned int value)
	{
		frame_end = value;
		load_image(image_name);
		ComputeFrameTimes();
	}

	std::string GetImageName()
	{
		return image_name;
	}

	void SetImageName(const std::string & value)
	{
		image_name = value;
		load_image(image_name);
	}

	virtual unsigned int GetImageIndexLength()
	{
		return 0;
	}

	virtual void SetImageIndexLength(unsigned int value)
	{
	}

	virtual std::string GetType() const
	{
		return "AbstractSequence";
	}
protected:
	void ComputeFrameTimes();
	virtual bool on_attribute(xml::Provider * prov, const std::string & name, const std::string & value);
	virtual bool on_node(xml::Provider * prov, const std::string & name);
	virtual bool on_end_node(xml::Provider * prov);
	virtual void on_save_attributes(xml::SaverBase * saver) const;

	virtual void load_image(const std::string & image_name) = 0;

	Atom name;
	std::string image_name;
	unsigned frame_start;
	unsigned frame_end;

	double frame_time;
	double height;
	double width;

	double loopDelay;
	FrameTimes frameTimes;

	std::vector<std::pair<size_t, double> > irregularDurations;
};

} // namespace anim2d
} // namespace lib3d

namespace converter
{

	template<>
	struct ConverterTraits<char, lib3d::anim2d::AbstractSequence::LoopType>
		:	public ConverterTraitsEnumBase<char, lib3d::anim2d::AbstractSequence::LoopType, lib3d::anim2d::AbstractSequence::LoopTypeNames>
	{};

} // namespace converter

} // namespace liba
using namespace liba;

